/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#ifndef CONTROLLER_H
#define CONTROLLER_H

#include "object.h"
#include "dataControl.h"
#include "analysisTool.h"
#include "renderUI.h"
#include "layout.h"
#include "colormap.h"
#include "shortcut.h"
#include <map>
#include <set>

#include <iostream>
#include <fstream>

class View;
class ViewManager;

using namespace std;
class Graph;
typedef set<string> stringArray;

typedef struct {
    string type;
    string name;
} ToolInfo;

typedef struct {
    string type;
    string name;
} ViewInfo;

typedef struct {
    string type;
    string name;
} LayoutInfo;


class PropertyListener {
public:
    virtual ~PropertyListener() {};
    virtual void propertyChanged(string name) = 0;
};
class ViewListener {
public:
    virtual ~ViewListener() {}
    virtual void viewAdded(View *view) = 0;
};

class LayoutListener {
public:
    virtual ~LayoutListener() {}
    virtual void layoutAdded(Layout *layout) = 0;
};
class DataListener {
public:
    virtual ~DataListener() {}
    virtual void dataAdded(const char * file, string event) = 0;
};

typedef View *(ViewCreatorFn)(string);
typedef Layout *(LayoutCreatorFn)(string);

// This is the controller. It knows all. Just like highlanders, there can be only one.
class Controller: public Object {
    RenderUI *renderUI;
    DataControl *dataControl;
    ViewManager * viewManager;

    map<string, ColorMap*> colormaps;

    map<string, int> stringMappings;
    map<string, int> stringMappingIndex;
    
    map<string, stringArray> mapProperties;
    map<string, string> virtualProperties;
    map<string, string> virtualPropertyTypes;

    map<string, Graph *> graphs;

    map<string, AnalysisTool *> tools;

    vector<PropertyListener *> listeners;

    map<string, View *> views;
    map<string, ViewCreatorFn *> viewCreators;
    map<string, int> numViewInstances;
    vector<ViewListener *> viewListeners;
	
    map<string, Layout *> layouts;
    map<string, LayoutCreatorFn *> layoutCreators;
    map<string, int> numLayoutInstances;
    vector<LayoutListener *> layoutListeners;

    vector<DataListener *> dataListeners;

	map<string, Shortcut *> shortcuts;
public:
    Controller();
    ~Controller();
    void importTable(Graph *g, const char *file);
    void importEdgeTable(Graph *g, const char *file, bool undirected = true);
    // Deprecated. Use exportTable and exportEdgeTable instead.
    void importFloat(Graph *g, const char *file, const char *property); // deprecated
    void exportFloat(Graph *g, const char *file, const char *property); // deprectaed
    void importImplicitEdgeFloat(Graph *g, const char *file, const char *property); // deprecated
    void exportImplicitEdgeFloat(Graph *g, const char *file, const char *property); // deprecated
    void importEdgeFloat(Graph *g, const char *file, const char *property); // deprecated
    void exportEdgeFloat(Graph *g, const char *file, const char *property); // deprecated

    void exportTable(Graph *g, const char *file, vector<string> properties, bool *filter=NULL);
    void exportEdgeTable(Graph *g, const char *file, vector<string> properties, bool *filter);
    void exportEdgeTable(Graph *g, const char *file, vector<string> properties);

    void updateRender();
    void setRenderUI(RenderUI *renderUI);
    RenderUI *getRenderUI();

    // Data
    vector<string> sources;

    void addDataListener(DataListener *p);
    void notifyDataAdded(const char *source, string event);

    // Graphs
    void addGraph(string name, Graph *g);
    Graph * getGraph(string name);

    // Tools
    void addTool(AnalysisTool *t);
    void executeTool(string name);
    AnalysisTool* getTool(string name);
    vector<ToolInfo> getTools();
    void setToolProperty(AnalysisTool *tool, string prop, string value);

    // Views
    void setViewManager(ViewManager *manager) { viewManager = manager;}
    ViewManager *getViewManager() { return viewManager;}
    void addView(View *t);
    vector<ViewInfo> getViews();
    View *getView(string name);
    View *createView(string type, string name);

    void addViewCreator(string type, ViewCreatorFn fn);
    vector<string> getViewCreators();
    void addViewListener(ViewListener *p);
    void notifyViewAdded(View *view);

    void setViewProperty(View *view, string prop, string value);

    // Layouts
    void addLayout(Layout *t);
    vector<LayoutInfo> getLayouts();
    Layout *getLayout(string name);
    Layout *createLayout(string type, string name);
    void executeLayout(string name);

    void addLayoutCreator(string type, LayoutCreatorFn fn);
    vector<string> getLayoutCreators();
    void addLayoutListener(LayoutListener *p);
    void notifyLayoutAdded(Layout *layout);
    void setLayoutProperty(Layout *layout, string prop, string value);
    void layoutUpdated();

    // Properties
    void registerProperty(string type, string prop);
    vector<string> getRegisteredProperties(string type);
    vector<string> getRegisteredLists();

    void addPropertyListener(PropertyListener *p);
    void notifyPropertyChanged(string name);
    void execute(string cmd, const char* file, const char* property);
    void readScript(const char *name);

    // Workspace
    bool loadWorkspace(const char *name);
    bool saveWorkspace(const char *name);

    // Property Management
    map<string, int> propertyTypes;
    void addDataProperty(string element, string name, int type);
    int getPropertyType(string name);

    // Color
    void getColor(string cmap, float f, float *rgb);
    void getColor(string cmap, int i, float *rgb);
    void addColormap(string name, ColorMap *c);
    ColorMap * getColormap(string name);
    void colorUpdated();

    // String Management  (For automatically creating mappings between string data values to integer codes)
    vector<string> getStringValues(string property);
    int numStringValues(string property);
		void addStringMapping(string property, string value, int index);
    void addStringMapping(string property, string value);
    int stringToInt(string property, string value);
    string intToString(string property, int value);

    // Search
    void doSearch(string searchStr);

    // Virtual Properties
    bool isVirtualProperty(string name);
    string extractPropertyName(string virtualName);

		static string addVirtualPrefix(string property);		

    vector<string> getVirtualProperties();
    string addVirtualProperty(string virtualName, string type);
    void setVirtualProperty(string virtualName, string dataName);
    string getVirtualProperty(string virtualName);
    string getVirtualPropertyType(string virtualName);
	
		// Shortcuts
		void addShortcut(Shortcut *shortcut);
		Shortcut *getShortcut(string name);
		vector<string> getShortcutNames();

    // this method is for QT creator IDE debug... where the active path is /netzen/src/
    bool retryOpenFile(const char *file, string &strFileReturn){
        strFileReturn = "";

        string strFile2 = "../";
        strFile2.append(file);

        ifstream inp(strFile2.c_str(), ifstream::in);

        bool ifSuccess = false;
        if(inp.is_open()){
            strFileReturn = strFile2;
            ifSuccess = true;
            inp.close();
        }
        else{
            ifSuccess = false;
        }
        return ifSuccess;
    }

};

#endif
